//
//  SFAudioPlayer.m
//  Test
//
//  Created by xueshan1 on 2018/11/13.
//  Copyright © 2018年 xueshan1. All rights reserved.
//

#import "SFAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>

//asset key
NSString *const SF1_Playable_Key = @"playable";
//playerItem key
NSString *const SF1_Status_Key = @"status";
NSString *const SF1_LoadedTimeRanges_Key = @"loadedTimeRanges";
NSString *const SF1_PlaybackBufferEmpty_Key = @"playbackBufferEmpty";
NSString *const SF1_PlaybackLikelyToKeepUp_Key = @"playbackLikelyToKeepUp";


@interface SFAudioPlayer ()
{
    BOOL _isInit;
}

@property(nonatomic,strong)NSURL *audioURL;
@property(nonatomic,strong)AVPlayer *player;
@property(nonatomic,strong)AVPlayerItem *playerItem;
 //进度观察者
@property(nonatomic,strong)id progressObserver;
//是否有其他声音播放
@property(nonatomic,assign)BOOL isOtherPlaying;
//在后台
@property(nonatomic,assign)BOOL isBackground;

@end

@implementation SFAudioPlayer

+ (instancetype)shareInstance{
    static SFAudioPlayer *audioPlayer = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        audioPlayer = [[SFAudioPlayer alloc]init];
    });
    return audioPlayer;
}
- (void)dealloc{
    [[NSNotificationCenter defaultCenter]removeObserver:self];
    [self sf_deallocPlayer];
}

//初始化
- (void)initPlayer{
    _isInit = YES;
    //默认值
    self.isBackground = NO;
    [[AVAudioSession sharedInstance]setActive:YES error:nil];
    self.isOtherPlaying = [AVAudioSession sharedInstance].isOtherAudioPlaying;
    self.sessionCategory = SFAudioPlayerSessionCategory_Playback;
    self.needCustomeCache = NO;
    self.receiveRemoteControl = NO;
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_appWillResignActive) name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_appDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_audioPlayerInterrupted:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:)   name:AVAudioSessionRouteChangeNotification object:nil];
 
    
}
//播放一个音频
- (void)sf_playAudioWithURLString:(NSString *)audioURLString isLocalFile:(BOOL)isLocal{
    if (!audioURLString.length) {
        return;
    }
    [self sf_playAudioWithURL:[NSURL URLWithString:audioURLString] isLocalFile:isLocal];
}

- (void)sf_playAudioWithURL:(NSURL *)audioURL isLocalFile:(BOOL)isLocal{
    if (![audioURL isKindOfClass:[NSURL class]]) {
        return;
    }
    if (!_isInit) {
        [self initPlayer];
    }
    self.audioURL = audioURL;
    [self sf_removeItemObserver];
    
    if (isLocal) {
        self.playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:audioURL.absoluteString]];
    }else{
        self.playerItem = [self loadItemWithURL:audioURL];
    }
    
    _player = [[AVPlayer alloc]init];
    
    [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
    
    [self sf_addItemObserver];
    
    if (self.receiveRemoteControl) {
        [self setPlayingCenterInfomation];
    }
    
    
}
- (AVPlayerItem *)loadItemWithURL:(NSURL *)audioURL{
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:audioURL options:nil];
//    if (self.needCustomeCache) [asset.resourceLoader setDelegate:self.resourceLoader queue:dispatch_get_main_queue()];
    [asset loadValuesAsynchronouslyForKeys:@[SF1_Playable_Key] completionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (!asset.isPlayable) {
                NSLog(@"不能播放");
                if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayFailed:)]) {
                    [self.delegate sf_playerPlayFailed:@"url不能播放"];
                }
                self.playState = SFAudioPlayerState_Failed;
                [asset cancelLoading];
            }
            
        });
    }];
    
    return [AVPlayerItem playerItemWithAsset:asset];
}

//播放
- (void)sf_audioPlay{
    if (self.playState == SFAudioPlayerState_Failed || self.playState == SFAudioPlayerState_Stopped) {
        [self sf_playAudioWithURL:self.audioURL isLocalFile:YES];
    }else{
        self.playState = SFAudioPlayerState_ReadyPlay;
        [self.player play];
        
    }
}
//暂停
- (void)sf_audioPause{
    self.playState = SFAudioPlayerState_Pause;
    [self.player pause];
}
//释放播放器
- (void)sf_deallocPlayer{
    [self sf_audioPause];
    //解除激活,并还原其他应用播放器声音
    if (self.isOtherPlaying) {
        [[AVAudioSession sharedInstance]setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
    }else{
        [[AVAudioSession sharedInstance]setActive:NO error:nil];
    }
    [self sf_removeItemObserver];
    
    if (self.player) {
        self.player = nil;
    }
    [self.player.currentItem cancelPendingSeeks];
    [self.player.currentItem.asset cancelLoading];
    
//    [self.resourceLoader stopLoadding];
    self.playState = SFAudioPlayerState_Stopped;
    
}

//重新播放
- (void)recyclePlay{
    if (!self.player) {
        return;
    }
    [self.player seekToTime:CMTimeMake(0, 1)];
    [self sf_audioPlay];
    
}
#pragma mark - notification
//播放结束
- (void)sf_playerDidPlayToEndTime:(NSNotification *)notification{
//    NSLog(@"播放结束");
    self.playState = SFAudioPlayerState_Stopped;
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerDidPlayToEndTime:)]) {
        [self.delegate sf_playerDidPlayToEndTime:self];
    }
    
    if (self.isRecyclePlay) {
        [self recyclePlay];
    }
    
}
//被打断(其他音频/来电话)
- (void)sf_audioPlayerInterrupted:(NSNotification *)notification{
    NSDictionary *dic = notification.userInfo;
    if ([dic[AVAudioSessionInterruptionTypeKey] integerValue] == 1) {
        NSLog(@"被打断");
        [self sf_audioPause];
        [[NSNotificationCenter defaultCenter]postNotificationName:@"pauseSendSimaUsetime" object:nil];
    }else{
        NSLog(@"打断结束");
        if ([dic[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue] == 1) {
//            [self sf_audioPlay];
        }
    }
    
}
- (void)sf_appWillResignActive{
    self.isBackground = YES;
}
- (void)sf_appDidBecomeActive{
    NSLog(@"audioplayer - sf_appDidBecomeActive");
    self.isBackground = NO;
}
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification {
    NSDictionary *interuptionDict = notification.userInfo;
    NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
    switch (routeChangeReason) {
        case AVAudioSessionRouteChangeReasonNewDeviceAvailable: {
            NSLog(@"耳机插入");
//            [self sf_audioPlay];
        }
            break;
        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: {
            NSLog(@"耳机拔出");
            [self sf_audioPause];
            [[NSNotificationCenter defaultCenter]postNotificationName:@"pauseSendSimaUsetime" object:nil];
        }
            break;
        case AVAudioSessionRouteChangeReasonCategoryChange:
            // called at start - also when other audio wants to play
            NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
            break;
    }
}

- (void)sf_removeItemObserver{
    if (self.player.currentItem) {
        [self.player.currentItem removeObserver:self forKeyPath:SF1_Status_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF1_LoadedTimeRanges_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF1_PlaybackBufferEmpty_Key];
        [self.player.currentItem removeObserver:self forKeyPath:SF1_PlaybackLikelyToKeepUp_Key];
    }
    
    if (self.player) {
        [[NSNotificationCenter defaultCenter]removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
        [self.player removeTimeObserver:self.progressObserver];
        _progressObserver = nil;
    }
    
}
- (void)sf_addItemObserver{
    
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(sf_playerDidPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF1_Status_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF1_LoadedTimeRanges_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF1_PlaybackBufferEmpty_Key options:NSKeyValueObservingOptionNew context:nil];
    [self.player.currentItem addObserver:self forKeyPath:SF1_PlaybackLikelyToKeepUp_Key options:NSKeyValueObservingOptionNew context:nil];
    
    kWeakSelf
    self.progressObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        if (weakSelf.playState == SFAudioPlayerState_ReadyPlay || weakSelf.playState == SFAudioPlayerState_Buffering) {
            weakSelf.playState = SFAudioPlayerState_Playing;
        }
        
        weakSelf.sf_currentTime = (CGFloat)CMTimeGetSeconds(time);
        if (weakSelf.sf_totalTime) {
            weakSelf.sf_progress = weakSelf.sf_currentTime/weakSelf.sf_totalTime;
        }
//        NSLog(@"当前时间:%f,进度:%f",weakSelf.sf_currentTime,weakSelf.sf_progress);
        if (weakSelf.sf_progress > self.sf_bufferProgress) {
            weakSelf.playState = SFAudioPlayerState_Buffering;
        }
         
        if (weakSelf.isBackground && self.receiveRemoteControl) {
            [weakSelf updatePlayingCenterInfo];
        }
        //delegate
        if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(sf_player:progress:currentTime:totalTime:)]) {
            [weakSelf.delegate sf_player:weakSelf progress:weakSelf.sf_progress currentTime:weakSelf.sf_currentTime totalTime:weakSelf.sf_totalTime];
        }
        if (weakSelf.progressChangeBlock) {
            weakSelf.progressChangeBlock(weakSelf.sf_progress);
        }
    }];
    
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if (self.isBackground && self.playState == SFAudioPlayerState_Pause) {
        return;
    }
    if (object == self.player.currentItem) {
        if ([keyPath isEqualToString:SF1_Status_Key]) {
            switch (_playerItem.status) {
                case AVPlayerItemStatusUnknown:
                    self.playState = SFAudioPlayerState_Failed;
                    NSLog(@"AVPlayerItemStatusUnknown:未知错误");
                    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayFailed:)]) {
                        [self.delegate sf_playerPlayFailed:@"未知错误"];
                    }
                    break;
                case AVPlayerItemStatusReadyToPlay:
                    //准备播放
                    self.playState = SFAudioPlayerState_ReadyPlay;
//                    [self sf_audioPlay];
                    [self.player play];

                    break;
                case AVPlayerItemStatusFailed:
                    self.playState = SFAudioPlayerState_Failed;
                    NSLog(@"AVPlayerItemStatusFailed:准备失败");
                    NSLog(@"%@",self.player.error.description);
                    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayFailed:)]) {
                        [self.delegate sf_playerPlayFailed:@"准备失败"];
                    }
                    break;
                    
                default:
                    break;
            }
            
        }else if ([keyPath isEqualToString:SF1_LoadedTimeRanges_Key]){//缓存时间
            self.sf_totalTime = CMTimeGetSeconds(self.player.currentItem.duration);
//            NSLog(@"总时长:%f",self.sf_totalTime);
            [self addBufferProgressObserver];
        }else if ([keyPath isEqualToString:SF1_PlaybackBufferEmpty_Key]){//缓冲是空的 - 跳转后没数据
            if (self.playerItem.playbackBufferEmpty) {
                
            }
            self.playState = SFAudioPlayerState_Buffering;
            NSLog(@"empty: 缓冲是空的吗:%d",self.playerItem.playbackBufferEmpty);
        }else if ([keyPath isEqualToString:SF1_PlaybackLikelyToKeepUp_Key]){//缓冲达到可播放 - 跳转后有数据
            NSLog(@"缓冲达到可播放");
        }
        
    }
}
- (void)addBufferProgressObserver{
    CMTimeRange timeRange = [self.playerItem.loadedTimeRanges.firstObject CMTimeRangeValue];
    CGFloat startSeconds = CMTimeGetSeconds(timeRange.start);
    CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);
    if (self.sf_totalTime != 0) {
        self.sf_bufferProgress = (startSeconds + durationSeconds)/self.sf_totalTime;
    }
 
//    NSLog(@"缓冲进度:%f",self.sf_bufferProgress);
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_player:bufferProgress:totalTime:)]) {
        [self.delegate sf_player:self bufferProgress:self.sf_bufferProgress totalTime:self.sf_totalTime];
    }
    
}

#pragma mark - set
- (void)setSessionCategory:(SFAudioPlayerSessionCategory)sessionCategory{
    _sessionCategory = sessionCategory;
    switch (sessionCategory) {
        case SFAudioPlayerSessionCategory_Ambient:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryAmbient error:nil];
            break;
        case SFAudioPlayerSessionCategory_SoloAmbient:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategorySoloAmbient error:nil];
            break;
        case SFAudioPlayerSessionCategory_Playback:
            [[AVAudioSession sharedInstance]setCategory:AVAudioSessionCategoryPlayback error:nil];
            break;
            
        default:
            break;
    }
}
- (void)setPlayState:(SFAudioPlayerState)playState{
    NSLog(@"-playState:%lu",(unsigned long)playState);
    _playState = playState;
    if (self.delegate && [self.delegate respondsToSelector:@selector(sf_playerPlayState:)]) {
        [self.delegate sf_playerPlayState:playState];
    }
    
}
- (void)setSf_rate:(CGFloat)sf_rate{
    self.player.rate = sf_rate;
}
- (CGFloat)sf_rate{
    return self.player.rate;
}
- (void)setProgressValus:(CGFloat)progressValus{
    if (progressValus<0.0 || progressValus >1.0) {
        return;
    }
    _progressValus = progressValus;
     
    if (self.sf_bufferProgress >= progressValus) {
        [self sf_audioPause];
        [self.player seekToTime:CMTimeMake(floorf(self.sf_totalTime*progressValus), 1) toleranceBefore:CMTimeMake(1, 1) toleranceAfter:CMTimeMake(1, 1) completionHandler:^(BOOL finished) {
            if (finished) {
                NSLog(@"seekComplete!!");
                [self sf_audioPlay];
            }
        }];
    }
    
}

- (void)seeKToZeroAndPause{
    [self sf_audioPause];
    [[NSNotificationCenter defaultCenter]postNotificationName:@"pauseSendSimaUsetime" object:nil];
    [self.player seekToTime:kCMTimeZero toleranceBefore:CMTimeMake(1, 1) toleranceAfter:CMTimeMake(1, 1) completionHandler:^(BOOL finished) {
        if (finished) {
            NSLog(@"seekComplete!!");
 
        }
    }];
    
}

#pragma mark - Lock Screen
- (void)setPlayingCenterInfomation{
 
}

- (void)updatePlayingCenterInfo{
    NSDictionary *info=[[MPNowPlayingInfoCenter defaultCenter] nowPlayingInfo];
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:info];
    dic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = [NSNumber numberWithDouble:CMTimeGetSeconds(self.playerItem.currentTime)];
    dic[MPMediaItemPropertyPlaybackDuration] = [NSNumber numberWithDouble:CMTimeGetSeconds(self.playerItem.duration)];
    dic[MPNowPlayingInfoPropertyPlaybackRate] = [NSNumber numberWithFloat:self.sf_rate];
    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dic];
}


@end
